package com.wrupple.muba.common.shared;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.event.shared.EventBus;
import com.wrupple.muba.common.client.application.DataCallback;

public class ParallelProcess<I, O> implements Process<I, List<O>> {

	class StateCallback extends DataCallback<O> {

		private final List<O> results;
		private final StateTransition<List<O>> globalCallback;

		public StateCallback(StateTransition<List<O>> globalCallback,List<O> results) {
			super();
			assert results!=null;
			assert globalCallback !=null : "a callback must be provided for a parallel process to start";
			pending.add(this);
			this.results=results;
			this.globalCallback=globalCallback;
		}

		@Override
		public void execute() {
			int index = pending.indexOf(this);
			results.set(index, result);
			pending.remove(index);
			if (pending.isEmpty()) {
				globalCallback.setResultAndFinish(results);
			}
		}

	}

	private Context context;
	private List<State<I, O>> states;
	private List<DataCallback<O>> pending;
	

	public ParallelProcess(List<State<I, O>> statelist) {
		super();
		this.states = statelist;
	}


	@Override
	public void setContext(com.wrupple.muba.common.shared.State.Context context) {
		this.context = context;
	}

	@Override
	public void start(I parameter, final StateTransition<List<O>> onDone,
			EventBus eventBus) {
		
		List<O> results = new ArrayList<O>(states.size());
		pending = new ArrayList<DataCallback<O>>(states.size());
		for(int i = 0 ; i < states.size(); i++){
			results.add(null);
		}
		
		StateCallback callback;
		for (State<I, O> state : states) {
			callback = new StateCallback(onDone, results);
			state.start(parameter, callback, eventBus);
		}


	}


	@Override
	public void addState(State<?, ?> state) {
		// all are expected to be of the same type
		states.add((State<I, O>) state);
	}

	@Override
	public com.wrupple.muba.common.shared.State.Context getContext() {
		return context;
	}

	@Override
	public Iterator<State<?, ?>> iterator() {
		Iterator regreso = this.states.iterator();
		return regreso;
	}

	@Override
	public void restore(com.wrupple.muba.common.shared.State.Context context) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void addAll(Process<?, ?> process) {
		for(State<?,?> s : process){
			addState(s);
		}
	}

	@Override
	public void suspend() {
		// TODO Auto-generated method stub
		
	}

}
